/*
 * This file is part of b.AMP.
 *
 * b.AMP is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * b.AMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __BAMP_ASYNC_LOOP_HPP__
#define __BAMP_ASYNC_LOOP_HPP__

#include "runnable.hpp"
#include <bamp/noncopyable.hpp>
#include <memory>

namespace bamp
{

    /**
     * An asynchronous loop is a loop that runs in its own thread. It
     * features a single method that is executed in a loop and a mechanism
     * to start and stop that loop.
     */
    class AsyncLoop : public bamp::Noncopyable, public Runnable {


    public:

        /**
         * Constructor. Do nothing yet.
         */
        AsyncLoop();

        /**
         * Destructor. If the thread is running, it will be
         * interrupted and detached. To avoid unwanted behavior,
         * consider calling stop() and waitStop() before destruction
         * happens.
         */
        virtual ~AsyncLoop();


        /**
         * Run the loop.
         * @return whether the thread could be started
         */
        virtual bool run();

        /**
         * Request that the loop be stopped as soon as possible.
         */
        virtual void stop();

        /**
         * Wait until the loop has stopped, usually after a call to
         * stop().
         */
        virtual void waitStop();

        /**
         * Check whether the loop is running.
         * @return true if the thread is running, false otherwise
         */
        virtual bool isRunning();

        /**
         * Check whether the loop is stopping.
         * @return true if stop() has been called but the thread is still
         *          running, false otherwise.
         */
        virtual bool isStopping();


    private:

        virtual bool preRun()    = 0;
        virtual bool postRun()   = 0;
        virtual bool iteration() = 0;
        virtual bool preStop()   = 0;
        virtual void postStop()  = 0;


    private:

        // Implementation
        struct Implementation;
        std::auto_ptr<Implementation> pimpl;

        /**
         * Loop method that runs in a thread.
         */
        void loop();

    };

} // namespace bamp

#endif // __BAMP_ASYNC_LOOP_HPP__
